﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using TD.Interface.Controls;
using TD.TheGame;

/*
 * OFFENSE:
 *   
 *   WEAPON:
 *     (126, 324)
 *     (126, 528)
 *     
 *   AMMUNITION:
 *     (374, 324)
 *     (374, 528)
 * 
 * 
 * 
 * DEFENCE:
 *     
 *   CASTLE:
 *     (654, 324)
 *     (654, 528)
 *     (755, 426)
 *     (856, 324)
 *     (856, 528)
 *     
 *   AEGIS:
 *     (1056, 324)
 *     (1056, 528)
 */

namespace TD.Interface.Menus
{
    internal class ShopMenu : MenuBase
    {
        private Texture2D background;
        private string hintText;
        private string priceText;
        private string money;
        private Dictionary<string, ShopItem> items;

        public ShopMenu(Game1 game) :
            base(game)
        {
            this.DrawOrder = 0x08A00000;
            Game.Services.AddService(typeof(ShopMenu), this);
        }

        public override void Initialize()
        {
            hintText = string.Empty;
            priceText = string.Empty;
            money = string.Empty;
            items = new Dictionary<string, ShopItem>();
            
            base.Initialize();
        }

        protected override void LoadContent()
        {
            ((Game1)Game).TextureManager.LoadAsset("interface\\shop_background");
            background = ((Game1)Game).TextureManager.UseAsset("interface\\shop_background");

            base.LoadContent();
        }

        protected override void UnloadContent()
        {
            DisposeTexture(ref background);

            base.UnloadContent();
        }
        private void DisposeTexture(ref Texture2D texture)
        {
            if (texture != null)
            {
                texture.Dispose();
                texture = null;
            }
        }

        public override void Update(GameTime gameTime)
        {
            if (((Game1)Game).InputManager.IsKeyPressed(Keys.Space))
            {
                this.ExitMenu();
            }

            money = GetLevel().Points.ToString();
            EnableTrees();

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.Opaque);
            spriteBatch.Draw(background, new Rectangle(0, 0, 1280, 720), Color.White);
            spriteBatch.End();

            Color color = Color.FromNonPremultiplied(0x32, 0x32, 0x32, 0xFF);
            LevelComponent level = GetLevel();

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            // HINT
            spriteBatch.DrawString(font, hintText, new Vector2(26 + 8, 118 + 8), color);
            // WAVE
            spriteBatch.DrawString(font, (level.currLevel + 1).ToString(), new Vector2(978, 128), color);
            spriteBatch.DrawString(font, "15", new Vector2(1128, 128), color);
            // MONEY
            spriteBatch.DrawString(font, money, new Vector2(820, 44), color);
            spriteBatch.DrawString(font, priceText, new Vector2(1050, 44), color);
            spriteBatch.End();
            
            base.Draw(gameTime);
        }

        protected override List<DrawableGameComponent> AddItems()
        {
            List<DrawableGameComponent> items = new List<DrawableGameComponent>();

            // Offensive: Weapon
            {
                ShopItem weaponA = new ShopItem((Game1)Game, "shop_reload2", new Point(126, 324), "Reload your weapon much faster.", 5000, ItemState.Locked, Age.Present);
                weaponA.MouseClick += new ButtonBase.OnClick(this.BuyWeapon_A);
                items.Add(weaponA);
                this.items.Add("weapon_a", weaponA);


                ShopItem weaponB = new ShopItem((Game1)Game, "shop_reload1", new Point(126, 528), "Reload your weapon slightly faster!", 1000, ItemState.Available);
                weaponB.MouseClick += new ButtonBase.OnClick(this.BuyWeapon_B);
                items.Add(weaponB);
                this.items.Add("weapon_b", weaponB);
            }

            // Offensive: Ammunition
            {
                ShopItem ammoA = new ShopItem((Game1)Game, "shop_ammo2a", new Point(374, 324), "Use the best ammuntion available!", 10000, ItemState.Locked, Age.Present);
                ammoA.MouseClick += new ButtonBase.OnClick(this.BuyAmmo_A);
                items.Add(ammoA);
                this.items.Add("ammo_a", ammoA);

                ShopItem ammoB = new ShopItem((Game1)Game, "shop_ammo1a", new Point(374, 528), "Use improved ammuntion.", 5000, ItemState.Available);
                ammoB.MouseClick += new ButtonBase.OnClick(this.BuyAmmo_B);
                items.Add(ammoB);
                this.items.Add("ammo_b", ammoB);
            }

            // Defensive: Castle
            {
                ShopItem catapultA = new ShopItem((Game1)Game, "shop_catapult", new Point(654, 324), "Extend your left tower with a catapult.", 15000, ItemState.Locked, Age.Future);
                catapultA.MouseClick += new ButtonBase.OnClick(this.BuyCastle_CatapultA);
                items.Add(catapultA);
                this.items.Add("castle_catapult_a", catapultA);

                ShopItem catapultB = new ShopItem((Game1)Game, "shop_catapult", new Point(856, 324), "Extend your right tower with a catapult.", 15000, ItemState.Locked, Age.Future);
                catapultB.MouseClick += new ButtonBase.OnClick(this.BuyCastle_CatapultB);
                items.Add(catapultB);
                this.items.Add("castle_catapult_b", catapultB);

                ShopItem towerA = new ShopItem((Game1)Game, "shop_castle1", new Point(755, 426), "Extend your castle with a central tower.", 8000, ItemState.Locked, Age.Present);
                towerA.MouseClick += new ButtonBase.OnClick(this.BuyCastle_A);
                items.Add(towerA);
                this.items.Add("castle_tower_a", towerA);

                ShopItem towerB = new ShopItem((Game1)Game, "shop_castle2", new Point(654, 528), "Extend your castle with a left tower.", 5000, ItemState.Available);
                towerB.MouseClick += new ButtonBase.OnClick(this.BuyCastle_B);
                items.Add(towerB);
                this.items.Add("castle_tower_b", towerB);

                ShopItem towerC = new ShopItem((Game1)Game, "shop_castle2", new Point(856, 528), "Extend your castle with a right tower.", 5000, ItemState.Available);
                towerC.MouseClick += new ButtonBase.OnClick(this.BuyCastle_C);
                items.Add(towerC);
                this.items.Add("castle_tower_c", towerC);
            }

            // Defensive: Aegis
            {
                ShopItem aegisA = new ShopItem((Game1)Game, "shop_fence3", new Point(1056, 324), "Place a advanced fence to protect your castle.", 7500, ItemState.Locked, Age.Future);
                aegisA.MouseClick += new ButtonBase.OnClick(this.BuyAegis_A);
                items.Add(aegisA);
                this.items.Add("aegis_a", aegisA);

                ShopItem aegisB = new ShopItem((Game1)Game, "shop_fence2", new Point(1056, 426), "Place a fence to protect your castle.", 4000, ItemState.Locked, Age.Present);
                aegisB.MouseClick += new ButtonBase.OnClick(this.BuyAegis_B);
                items.Add(aegisB);
                this.items.Add("aegis_b", aegisB);

                ShopItem aegisC = new ShopItem((Game1)Game, "shop_fence1", new Point(1056, 528), "Place a simple fence to protect your castle.", 1500, ItemState.Available);
                aegisC.MouseClick += new ButtonBase.OnClick(this.BuyAegis_C);
                items.Add(aegisC);
                this.items.Add("aegis_c", aegisC);
            }

            // Add the hint methods.
            foreach (DrawableGameComponent component in items)
            {
                ShopItem item = component as ShopItem;
                if (item != null)
                {
                    item.MouseHover += new ShopItem.OnHover(this.SetHint);
                    item.MouseLeave += new ShopItem.OnLeave(this.ClearHint);
                }
            }

            return items;
        }

        protected override void HandleEnabledChanged(object sender, EventArgs e)
        {
            // Do something...
        }

        protected override void HandleVisibleChanged(object sender, EventArgs e)
        {
            // Do something...
        }

        protected override void UpdateItems(List<DrawableGameComponent> items, GameTime gameTime)
        {
            // Do something...
        }

        private void SetHint(object sender)
        {
            ShopItem item = sender as ShopItem;
            if (item != null)
            {
                hintText = item.Hint;
                priceText = item.Price.ToString();
            }
        }

        private void ClearHint(object sender)
        {
            hintText = string.Empty;
            priceText = string.Empty;
        }

        #region Buy
        private bool HasSufficientMoney(object sender)
        {
            ShopItem item = (ShopItem)sender;
            LevelComponent level = GetLevel();

            if (level.Points >= item.Price)
            {
                level.Points -= item.Price;
                item.State = ItemState.Bought;
                return true;
            }
            else
            {
                hintText = "You need more money!";
                item.State = ItemState.Available;
            }

            return false;
        }

        private T GetService<T>()
        {
            return (T)Game.Services.GetService(typeof(T));
        }

        private PlayerComponent GetPlayer()
        {
            return GetService<PlayerComponent>();
        }

        private Castle GetCastle()
        {
            return GetService<Castle>();
        }

        private LevelComponent GetLevel()
        {
            return GetService<LevelComponent>();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        private void BuyWeapon_A(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                PlayerComponent player = GetPlayer();
                player.ReloadTime = (player.ReloadTime * 80 / 100);
                PlayCompleted();
            }
        }

        private void BuyWeapon_B(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                PlayerComponent player = GetPlayer();
                player.ReloadTime = (player.ReloadTime * 80 / 100);
                PlayUpdated();
            }
        }

        private void BuyAmmo_A(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                PlayerComponent player = GetPlayer();
                player.updateArrows(SpriteEnumState.Future, 200);
                PlayCompleted();
            }
        }

        private void BuyAmmo_B(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                PlayerComponent player = GetPlayer();
                player.updateArrows(SpriteEnumState.Normal, 100);
                PlayUpdated();
            }
        }

        /// <summary>
        /// Buy the catapult for the left tower.
        /// </summary>
        /// <param name="sender"></param>
        private void BuyCastle_CatapultA(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                Castle castle = GetCastle();
                castle.UpgradeLeftSideTower(SpriteEnumState.Shoot);
                PlayCompleted();
            }
        }

        /// <summary>
        /// Buy the catapult for the right tower.
        /// </summary>
        /// <param name="sender"></param>
        private void BuyCastle_CatapultB(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                Castle castle = GetCastle();
                castle.UpgradeRightSideTower(SpriteEnumState.Shoot);
                PlayCompleted();
            }
        }

        /// <summary>
        /// Buy the central tower of the castle.
        /// </summary>
        /// <param name="sender"></param>
        private void BuyCastle_A(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                Castle castle = GetCastle();
                castle.EnableMidTopTower();
                PlayCompleted();
            }
        }

        /// <summary>
        /// Buy the left tower of the castle.
        /// </summary>
        /// <param name="sender"></param>
        private void BuyCastle_B(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                Castle castle = GetCastle();
                castle.EnableLeftSideTower();
                PlayUpdated();
            }
        }

        /// <summary>
        /// Buy the right tower of the castle.
        /// </summary>
        /// <param name="sender"></param>
        private void BuyCastle_C(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                Castle castle = GetCastle();
                castle.EnableRightSideTower();
                PlayUpdated();
            }
        }

        private void BuyAegis_A(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                Castle castle = GetCastle();
                castle.UpdateCastleFence(SpriteEnumState.Future, 1000, 100);
                PlayCompleted();
            }
        }

        private void BuyAegis_B(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                Castle castle = GetCastle();
                castle.UpdateCastleFence(SpriteEnumState.Normal, 500, 50);
                PlayUpdated();
            }
        }

        private void BuyAegis_C(object sender)
        {
            if (HasSufficientMoney(sender))
            {
                Castle castle = GetCastle();
                castle.UpdateCastleFence(SpriteEnumState.Past, 250, 25);
                PlayUpdated();
            }
        }
        #endregion

        private void PlayCompleted()
        {
            SoundManager manager = ((Game1)Game).SoundManager;
            manager.LoadAsset("objective_completed");
            manager.Play("objective_completed");
        }

        private void PlayUpdated()
        {
            SoundManager manager = ((Game1)Game).SoundManager;
            manager.LoadAsset("objective_updated");
            manager.Play("objective_updated");
        }

        private void EnableTrees()
        {
            /**
             * Weapon
             */
            Unlock("weapon_b", "weapon_a");

            /**
             * Ammunition
             */
            Unlock("ammo_b", "ammo_a");

            /**
             * Castle
             */
            Unlock("castle_tower_b", "castle_tower_c", "castle_tower_a");
            Unlock("castle_tower_b", "castle_catapult_a");
            Unlock("castle_tower_c", "castle_catapult_b");

            /**
             * Aegis
             */
            Unlock("aegis_c", "aegis_b");
            Unlock("aegis_c", "aegis_b", "aegis_a");
        }

        /// <summary>
        /// Unlock a specific item.
        /// </summary>
        /// <param name="boughtA">The reference name of an additional item that has to be bought.</param>
        /// <param name="boughtB">The reference name of the item that has to be bought.</param>
        /// <param name="key">The reference name of the item to unlock.</param>
        private void Unlock(string boughtA, string boughtB, string key)
        {
            if (items[boughtA].State == ItemState.Bought)
            {
                Unlock(boughtB, key);
            }
        }

        /// <summary>
        /// Unlock a specific item.
        /// </summary>
        /// <param name="bought">The reference name of the item that has to be bought.</param>
        /// <param name="key">The reference name of the item to unlock.</param>
        private void Unlock(string bought, string key)
        {
            if (items[bought].State == ItemState.Bought)
            {
                ShopItem item = items[key];

                if (item.State == ItemState.Locked)
                {
                    LevelComponent level = GetLevel();
                    int curAge = (int)level.CurrentAge;
                    int unlAge = (int)item.UnlockedAt;

                    if (curAge >= unlAge)
                    {
                        items[key].State = ItemState.Available;
                    }
                }
            }
        }
    }
}
